/**
 * 消息发送类
 * 1. 实现消息队列
 * 2. 实现消息节流发送
 * 3. 实现消息延迟发送
 * 4. 消息发送失败统一监控
 */
import { User } from '../models';
const DELAY_TIMESET = 30 * 60 * 1000; // 延迟发送时间
const INSPECT_INTERVAL = 3 * 60 * 1000; // 巡检间隔

export interface IMessageSenderProps {
  inspectInterval?: number; // 巡检时间间隔
  delayTimeset?: number; // 延迟发送时间
}

export interface IMessageItem {
  type: IMessageType;
  userid: string;
  bookid: string;
  sendTime: number;
  nextSendTime: number;
  data?: any;
  extra?: any;
}

export enum IMessageType {
  wxappBookUpdate = 'wxappBookUpdate', // 微信小程序书籍更新模板消息
  wxappComment = 'wxappComment', // 微信小程序书籍评论回复模板消息
  wxaccount = 'wxaccount', // 微信公众号消息
  app = 'app' // app 内部消息
}

class MessageSender {
  public messages: Record<string, IMessageItem[]>;
  public nextSendTime: number;
  public inspectInterval: number;
  public delayTimeset: number;

  constructor(props: IMessageSenderProps) {
    this.messages = {};
    this.inspectInterval = props.inspectInterval || INSPECT_INTERVAL;
    this.delayTimeset = props.delayTimeset || DELAY_TIMESET;
    this.nextSendTime = Date.now() + this.delayTimeset;
    this.setNextSendTimeClock();
    this.inspect();
  }

  /**
   * 将消息加入队列
   * @param type 消息类型
   * @param userid 用户 id
   * @param bookid 书籍 id
   * @param data 消息详情数据
   * @param extra 额外数据
   */
  add(type: IMessageType, userid, bookid: string, data: any, extra: any) {
    if (!this.messages[bookid]) this.messages[bookid] = [];
    const existItemIndex = this.messages[bookid].findIndex(item => {
      return item.userid.toString() === userid.toString();
    });
    const currentMessage = {
      type,
      userid,
      bookid,
      data,
      extra,
      sendTime: Date.now() + this.delayTimeset,
      nextSendTime: this.nextSendTime
    };
    // 如果相同书籍相同用户已经存在消息，则清除
    if (existItemIndex > -1) {
      this.messages[bookid].splice(existItemIndex, 1, currentMessage);
    } else {
      this.messages[bookid].push(currentMessage);
    }
  }

  /**
   * 查找相同类型，相同书籍，相同用户的消息
   */
  findSameMessageIndex(curMsg: IMessageItem, msgs: IMessageItem[]) {
    if (!msgs) return -1;
    if (msgs.length === 0) return -1;
    for (let i = 0; i < msgs.length; i++) {
      if (msgs[i].type === curMsg.type && msgs[i].bookid === curMsg.bookid && msgs[i].userid === curMsg.userid) {
        return i;
      }
      continue;
    }
    return -1;
  }

  /**
   * 消息巡检
   * 消息 sendTime 小于或者等于当前时间立即发送，随后删除消息
   */
  private inspect() {
    setInterval(() => {
      const nowTimeset = Date.now();
      const waitSendMsgs = [] as IMessageItem[];
      Object.keys(this.messages).forEach(bookid => {
        this.messages[bookid] = this.messages[bookid].filter((message: IMessageItem) => {
          if (nowTimeset >= message.sendTime) {
            const existedIndex = this.findSameMessageIndex(message, waitSendMsgs);
            if (existedIndex < 0) {
              waitSendMsgs.push(message);
            } else {
              // 对于在相同巡检周期内将发送时间滞后的消息替换进去
              if (message.sendTime >= waitSendMsgs[existedIndex].sendTime && message.nextSendTime === waitSendMsgs[existedIndex].nextSendTime) {
                waitSendMsgs.splice(existedIndex, 1, message);
              }
            }
            return false;
          }
          return true;
        });
      });
      // 开始发送
      this.send(waitSendMsgs);
    }, this.inspectInterval);
  }

  private setNextSendTimeClock() {
    setInterval(() => {
      this.nextSendTime += this.delayTimeset;
    }, this.delayTimeset);
  }

  private send(msgs: IMessageItem[]) {
    if (!msgs) return;
    msgs.forEach(msg => {
      if (msg.type === IMessageType.wxappBookUpdate) {
        (User as any).sendMessage(msg.userid, 'book-update', msg.data, msg.extra);
      }
      // 拓展其他消息类型
    });
  }
}

const MessageSenderInstance = new MessageSender({});

export default MessageSender;
export { MessageSenderInstance };
